<?php

require_once MNET_DIR.'/mnet_extension.php';

/**
 * The enrolment extension is used to remotely enrol users into courses
 *
 */
abstract class mnet_extension_enrolment extends mnet_extension {
  
  /**
   * RPC request handler for fetch_remote_courses()
   *
   * Will return a list of courses available on this host
   * 
   * Each course should have fields:
   *  - remoteid          (the ID)
   *  - cat_id            (catalogue ID)
   *  - cat_name          (catalogue name)
   *  - cat_description   (catalogue description)
   *  - sortorder         (course sort order, relative to the others we're returning)
   *  - fullname          (the long name for the course)
   *  - shortname         (the short name for the course)
   *  - idnumber          (the institution ID number for the course (business key))
   *  - summary           (course summary)
   *  - startdate         (date when the course starts, UNIX timestamp)
   *  - cost              (how much the course costs, float)
   *  - currency          (which currency code, 3-letter ISO code, eg. USD)
   *  - defaultroleid     (the default role ID for this course, moodle specific, see mdl_role in Moodle)
   *  - defaultrolename   (the name of the default role, eg. 'student', again, Moodle specific probably)
   *
   * @return array an array of associative array course records with the above fields
   */
  public function rpc_available_courses() {
    return $this->get_local_courses();
  }

  /**
   * Must be implemented and return an array of course records in the format
   * documented for rpc_available_courses()
   * 
   * @return array an array of associative array course records with the above fields
   */
  protected abstract function get_local_courses();

  /**
   * Return the usernames of students enroled in the specified course ID.
   * You may optionally specify a CSV (urgh) list of role 'shortnames' to find
   * only enrolemnents of that type.
   * 
   * @param string $course_id the course ID on this peer
   * @param string $roles CSV list of roles string. If not supplied, will return users of all roles
   * @return array an assoc array keyed by username, see get_course_enrolments() 
   */
  public function rpc_course_enrolments($course_id, $roles = '') {
    $roles = explode(',', $roles);
    $roles = array_filter(array_map($roles, 'trim'));
    $peer = mnet_server::get_current_client();
    return $this->get_local_enrolments($peer, $course_id, $roles);
  }

  /**
   * Must be implemented and return an array of usernames that are enroled
   * in the specified course (by ID) and have a role within the list of roles.
   * 
   * If the role list is empty, return users of all roles
   * 
   * @param mnet_peer the peer context for users. Don't return users not in this peer context.
   * @param string $course_id the local course ID of the course
   * @param array $roles an array of role short names
   * @return array an array of username strings
   */
  protected abstract function get_local_enrolments(mnet_peer $peer, $course_id, $roles);

  /**
   * Enrol a user in a course, if they're not already enroled.
   * Note that in Moodle at least, the username must be an MNet user
   * registered to the calling peer.
   * 
   * @param string $username the user's username on this host
   * @param string $course_id the course ID on this host
   * @return bool true if the enrolment was successful or they were already enroled
   */
  public function rpc_enrol_user($username, $course_id) {
    $peer = mnet_server::get_current_client();
    return $this->enrol_user_in_course($peer, $username, $course_id);
  }

  /**
   * Must be implemented and enrols a user of this peer context into a course. If the
   * user is already enroled, make sure they have a role at least equivalent to the default
   * role in that course, and return true. If the user can't be found or the course can't be found,
   * return false.
   * 
   * The user should be enroled with the default role for that course if they're not already enroled.
   * 
   * @param mnet_peer $peer the peer context for the user. Refuse the enrolment if there's no user of this context
   * @param string $username the username within the peer context
   * @param string $course_id the course ID to enrol them in
   */
  protected abstract function enrol_user_in_course(mnet_peer $peer, $username, $course_id);

  /**
   * RPC handler to unenrol a student from a course
   * 
   * @param string $username the user's username
   * @param string $course_id the course's ID
   * @return bool true if successful 
   */
  public function rpc_unenrol_user($username, $course_id) {
    
  }
  
  /**
   * Unenrol a user from a course, removing all their roles. The user must be within the supplied
   * peer context.
   * 
   * @param mnet_peer $peer the peer context for the user
   * @param string $username the user's username, within the peer context
   * @param string $course_id the course ID
   * @return bool true on success, or if the user wasn't enroled, or false if the user or course doesn't exist
   */
  protected abstract function unenrol_user_from_course(mnet_peer $peer, $username, $course_id);
  
  
  // *** CLIENT FUNCTIONS ***
  
  /**
   * Fetch a list of courses on the remote peer
   * 
   * @param mnet_peer $peer the peer to fetch courses from
   * @return array an array of course records, see rpc_available_courses() for format
   */
  public function fetch_remote_courses(mnet_peer $peer) {
    $client = new mnet_client();
    if ($peer->get_protocol() == 1) {
      $client->set_method('enrol/mnet/enrol.php/available_courses');
    }
    else {
      $client->set_method('mnet/enrolment/available_courses');
    }

    return $client->send($peer);
  }

  /**
   * Request that a user is enroled in a course on the remote peer with at least the default
   * role
   * 
   * @param mnet_peer $peer the peer to register them on
   * @param string $username the user's username
   * @param string $course_id the remote course ID
   * @return bool true on success 
   */
  public function req_enrol_user(mnet_peer $peer, $username, $course_id) {
    $client = new mnet_client();
    if ($peer->get_protocol == 1) {
      $client->set_method('enrol/mnet/enrol.php/enrol_user');
    }
    else {
      $client->set_method('mnet/enrolment/enrol_user');
    }

    $client->add_param($username, 'string');
    $client->add_param($course_id, 'string');

    return $client->send($peer);
  }

  /**
   * Request that a user is unenroled from a course on the remote peer
   * 
   * @param mnet_peer $peer the peer to register them on
   * @param string $username the user's username
   * @param string $course_id the remote course ID
   * @return bool true on success 
   */
  public function req_unenrol_user(mnet_peer $peer, $username, $course_id) {
    $client = new mnet_client();
    if ($peer->get_protocol == 1) {
      $client->set_method('enrol/mnet/enrol.php/unenrol_user');
    }
    else {
      $client->set_method('mnet/enrolment/unenrol_user');
    }

    $client->add_param($username, 'string');
    $client->add_param($course_id, 'string');

    return $client->send($peer);
  }
  
  /**
   * Retrieves a list of usernames enroled in a remote peer's course, optionally only
   * those of particular roles
   * 
   * @param mnet_peer $peer the remote peer to get enrolments for
   * @param string $course_id the remote course ID
   * @param array $roles if desired, pass an array of role 'shortnames' to restrict by, or leave null for all roles
   * @return array an assoc array of usernames to an assoc array containing keys:
   *                 'enrol' (enrolment method, eg. manual)
   *                 'timemodified' (unix timestamp when the enrolment changed
   *                 'shortname'   (short name of their enrolment role
   *                 'name'        (long name of their enrolment role)
   *              Note these are only users that are local to us (we can't retrieve enrolment details for users that aren't from our local peer)
   */
  public function get_course_enrolments(mnet_peer $peer, $course_id, $roles = null) {
    $client = new mnet_client();
    if ($peer->get_protocol() == 1) {
      $client->set_method('enrol/mnet/enrol.php/course_enrolments');
    }
    else {
      $client->set_method('mnet/enrolment/course_enrolments');
    }
    
    $client->add_param($course_id, 'string');
    if ($roles) {
      $client->add_param(implode(',', $roles), 'string');
    }

    return $client->send($peer);
  }
}
